package org.wheel.plugins.toolkit.util;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * 线程安全、保持插入顺序、允许 null 值的 Map 实现。
 * 内部：HashMap（存数据） + ArrayList（存顺序）。
 * 并发：全局锁（putLock），简单可靠。
 *
 * @param <K> key type
 * @param <V> value type
 */
public class NullableConcurrentLinkedHashMap<K, V> implements Map<K, V> {

    /* =========================  字段  ========================= */

    /** 存数据：支持 null 值 */
    private final HashMap<K, V> map = new HashMap<>();

    /** 存插入顺序（不重复） */
    private final ArrayList<K> order = new ArrayList<>();

    /** 全局锁 */
    private final Object putLock = new Object();

    /* =========================  基本查询  ========================= */

    @Override
    public int size() {
        synchronized (putLock) { return map.size(); }
    }

    @Override
    public boolean isEmpty() {
        synchronized (putLock) { return map.isEmpty(); }
    }

    @Override
    public boolean containsKey(Object key) {
        synchronized (putLock) { return map.containsKey(key); }
    }

    @Override
    public boolean containsValue(Object value) {
        synchronized (putLock) { return map.containsValue(value); }
    }

    @Override
    public V get(Object key) {
        synchronized (putLock) { return map.get(key); }
    }

    /* =========================  修改操作  ========================= */

    @Override
    public V put(K key, V value) {
        synchronized (putLock) {
            V old = map.put(key, value);
            if (old == null && !order.contains(key)) {   // 第一次插入
                order.add(key);
            }
            return old;
        }
    }

    @Override
    public V remove(Object key) {
        synchronized (putLock) {
            V old = map.remove(key);
            if (old != null || order.contains(key)) {    // 确实存在过
                order.remove(key);
            }
            return old;
        }
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> m) {
        synchronized (putLock) {
            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
                put(e.getKey(), e.getValue());
            }
        }
    }

    @Override
    public void clear() {
        synchronized (putLock) {
            map.clear();
            order.clear();
        }
    }

    /* =========================  视图  ========================= */

    @Override
    public Set<K> keySet() {
        synchronized (putLock) {
            return new LinkedHashSet<>(order);   // 保持顺序
        }
    }

    @Override
    public Collection<V> values() {
        synchronized (putLock) {
            List<V> list = new ArrayList<>(order.size());
            for (K k : order) list.add(map.get(k));
            return Collections.unmodifiableList(list);
        }
    }

    @Override
    public Set<Entry<K, V>> entrySet() {
        synchronized (putLock) {
            Set<Entry<K, V>> set = new LinkedHashSet<>(order.size());
            for (K k : order) set.add(new AbstractMap.SimpleEntry<>(k, map.get(k)));
            return Collections.unmodifiableSet(set);
        }
    }

    /* =========================  JDK8 默认方法  ========================= */

    @Override
    public V getOrDefault(Object key, V defaultValue) {
        synchronized (putLock) {
            return map.getOrDefault(key, defaultValue);
        }
    }

    @Override
    public void forEach(BiConsumer<? super K, ? super V> action) {
        Objects.requireNonNull(action);
        synchronized (putLock) {
            for (K k : order) action.accept(k, map.get(k));
        }
    }

    @Override
    public V putIfAbsent(K key, V value) {
        synchronized (putLock) {
            V old = map.get(key);
            if (old == null) {
                map.put(key, value);
                if (!order.contains(key)) order.add(key);
            }
            return old;
        }
    }

    @Override
    public boolean remove(Object key, Object value) {
        synchronized (putLock) {
            if (map.remove(key, value)) {
                order.remove(key);
                return true;
            }
            return false;
        }
    }

    @Override
    public boolean replace(K key, V oldValue, V newValue) {
        synchronized (putLock) {
            if (map.replace(key, oldValue, newValue)) {
                if (!order.contains(key)) order.add(key);
                return true;
            }
            return false;
        }
    }

    @Override
    public V replace(K key, V value) {
        synchronized (putLock) {
            V old = map.replace(key, value);
            if (old != null && !order.contains(key)) order.add(key);
            return old;
        }
    }

    @Override
    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
        Objects.requireNonNull(function);
        synchronized (putLock) {
            for (K k : order) {
                V oldVal = map.get(k);
                V newVal = function.apply(k, oldVal);
                map.put(k, newVal);
            }
        }
    }

    @Override
    public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
        Objects.requireNonNull(mappingFunction);
        synchronized (putLock) {
            V old = map.get(key);
            if (old == null) {
                V computed = mappingFunction.apply(key);
                if (computed != null) {
                    map.put(key, computed);
                    if (!order.contains(key)) order.add(key);
                }
                return computed;
            }
            return old;
        }
    }

    @Override
    public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        synchronized (putLock) {
            V old = map.get(key);
            if (old != null) {
                V computed = remappingFunction.apply(key, old);
                if (computed != null) {
                    map.put(key, computed);
                    if (!order.contains(key)) order.add(key);
                } else {
                    map.remove(key);
                    order.remove(key);
                }
                return computed;
            }
            return null;
        }
    }

    @Override
    public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        synchronized (putLock) {
            V old = map.get(key);
            V computed = remappingFunction.apply(key, old);
            if (computed != null) {
                map.put(key, computed);
                if (old == null && !order.contains(key)) order.add(key);
                return computed;
            } else {
                if (old != null) {
                    map.remove(key);
                    order.remove(key);
                }
                return null;
            }
        }
    }

    @Override
    public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        synchronized (putLock) {
            V old = map.get(key);
            V newVal = (old == null) ? value : remappingFunction.apply(old, value);
            if (newVal != null) {
                map.put(key, newVal);
                if (old == null && !order.contains(key)) order.add(key);
            } else {
                map.remove(key);
                order.remove(key);
            }
            return newVal;
        }
    }

    /* =========================  额外顺序视图  ========================= */

    /** 按插入顺序返回 key 列表（副本） */
    public List<K> orderedKeys() {
        synchronized (putLock) {
            return new ArrayList<>(order);
        }
    }

    /** 按插入顺序返回 entry 列表（副本） */
    public List<Entry<K, V>> orderedEntries() {
        synchronized (putLock) {
            List<Entry<K, V>> list = new ArrayList<>(order.size());
            for (K k : order) list.add(new AbstractMap.SimpleEntry<>(k, map.get(k)));
            return list;
        }
    }
}
